#ifndef __WIZ_UTILS_STATE_MACHINE_STATE_PLANNED_HPP__SHANHAOBO_19800429__
#define __WIZ_UTILS_STATE_MACHINE_STATE_PLANNED_HPP__SHANHAOBO_19800429__

#include "../../Core/Container/WizDataTypeMap.hpp"
#include "../../Core/Container/WizDataTypeSet.hpp"

#include "../../DataType/SmartPtr/SharedPtr/WizDataTypeSharedPtr.hpp"

namespace Wiz
{
    namespace StateMachinePlanned
    {
        /// PREDECLARE
        template<class EventT, class NameT> class Type;

        //////////////////////////////////////////////////////////////////////////
        namespace State
        {
            template <class EventT, class NameT>
            class Type : public ::Wiz::Enable_SharedFromThis<Type<EventT, NameT>>
            {
                WIZ_DECLARE_CLASS_THIS(Type);
            public:
                typedef EventT                                      tEvent;
                typedef NameT                                       tName;
                typedef typename ::Wiz::TypeTraits::Remove::Reference<tName>::tType
                                                                    tNameOrgCV;
                typedef typename ::Wiz::TypeTraits::Remove::CV<tNameOrgCV>::tType
                                                                    tNameOrg;
                typedef tNameOrg&                                   tNameRef;
                typedef const tNameOrg&                             tNameRefConst;
                typedef ::Wiz::StateMachinePlanned::Type<tEvent, tName>
                                                                    tStateMachine;
            protected:
                typedef ::Wiz::Map::Type<tEvent, tName>             tTransTable;
            private:
                friend class tStateMachine;
            protected:
                Type(tStateMachine& InSM, tNameRefConst InName) : m_StateMachine(InSM), m_Name(InName)
                {
                    InSM.AddState(this->SharedFromThis());
                }
                virtual ~Type()
                {
                }
            public:
                tNameRefConst GetName() const
                {
                    return this->m_Name;
                }
                const tStateMachine& GetStateMachine() const
                {
                    return this->m_StateMachine;
                }
            public:
                ::Wiz::Bool::Type CloneTransTable(const tThisPtr InOther)
                {
                    if (this->m_TransTable.Size() > 0)
                    {
                        this->m_TransTable.Clear();
                    }

                    tTransTable::tIteratorConst Curr;
                    tTransTable::tForEachConst FE(Curr, InOther->m_TransTable);
                    while (FE.HasMoreElement())
                    {
                        m_TransTable.InsertUnique(Curr.GetIndex(), Curr.GetValue()) ;
                    }

                    return ::Wiz::Bool::True;
                }
                virtual ::Wiz::Bool::Type Clone(const tThisPtr InOther)
                {
                    return this->CloneTransTable(InOther);
                }
            public:
                ::Wiz::Bool::Type GetNextStateName(const tEvent& InEvt, tNameRef OutName) const
                {
                    tTransTable::tIteratorConst Found = m_TransTable.Find(InEvt);
                    if (Found == m_TransTable.End())
                    {
                        return ::Wiz::Bool::False;
                    }
                    OutName = Found.GetValue();
                    return ::Wiz::Bool::True;
                }

                tThisPtr GetNextState(const tEvent& InEvt) const
                {
                    tName NextStateName;
                    if (this->GetNextStateName(InEvt, NextStateName))
                    {
                        return this->m_StateMachine.GetStateByName(NextStateName);
                    }

                    WIZ_ASSERT(::Wiz::Bool::False);
                    return tThisPtr();
                }
            public:
                ::Wiz::Bool::Type AddNextState(const tEvent& InEvt, tNameRefConst InName)
                {
                    if (this->m_StateMachine.HasState(InName))
                    {
                        return this->m_TransTable.InsertUnique(InEvt, InName);
                    }

                    return ::Wiz::Bool::False;
                }
                ::Wiz::Bool::Type AddNextState(const tEvent& InEvt, const tThisPtr InNextPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(InNextPtr));
                    if (::Wiz::IsValidPtr(InNextPtr) && InNextPtr->IsBelongTo(this->m_StateMachine))
                    {
                        return this->m_TransTable.InsertUnique(InEvt, InNextPtr->GetName());
                    }

                    return ::Wiz::Bool::False;
                }
            public:
                ::Wiz::Bool::Type IsValid() const
                {
                    return (this->m_StateMachine.GetStateByName(this->m_Name).Get() == this);
                }
                ::Wiz::Bool::Type NotValid() const
                {
                    return this->IsValid() == ::Wiz::Bool::False;
                }
                /// Does the state belong to the specified StateMachinePlanned?
                ::Wiz::Bool::Type IsBelongTo(const tStateMachine& InSM) const
                {
                    return InSM.GetStateByName(this->m_Name).Get() == this;
                }
                ::Wiz::Bool::Type NotBelongTo(const tStateMachine& InSM) const
                {
                    return InSM.GetStateByName(this->m_Name).Get() != this;
                }
            public:
                virtual ::Wiz::Bool::Type FilterEvent(const tEvent&) = 0;
                virtual ::Wiz::Bool::Type Enter() = 0;
                virtual ::Wiz::Void::Type Exit() = 0;
            protected:
                tTransTable             m_TransTable;
            private:
                const tName             m_Name;
                const tStateMachine&    m_StateMachine;
            };
        } /// end of namespace State
    } /// end of namespace StateMachinePlanned
} /// end of namespace Wiz

#endif /*__WIZ_UTILS_STATE_MACHINE_STATE_PLANNED_HPP__SHANHAOBO_19800429__*/
